////////////////////////////////////////////////////////////////////////////////
//
//  FLEX USER GROUP HOKURIKU
//  Copyright 2009 Flex User Group Hokuriku
//  All Rights Reserved.
// 
//  NOTICE: Flex User Group Hokuriku permits you to use, 
//  modify, and distribute this file 
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package net.fxug.hokuriku.chocolat.model
{

    import flash.errors.IllegalOperationError;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    import flash.utils.getTimer;

    import net.fxug.hokuriku.chocolat.events.SessionTimerEvent;

    /**
     * タイマーモデルクラス
     *
     * @author shoito
     */
    public class SessionTimer extends EventDispatcher
    {
        private static var instance:SessionTimer;

        private const INTERVAL:int = 1000;

        private var _utilTimer:Timer;

        /** タイマー開始時間 */
        private var _startTime:int;

        /** セッションタイム設定値 */
        private var _period:int;

        /** セッションボーナスタイム(セッションタイムに占める時間) */
        private var _bonus:int;

        private var _adjustedBonus:int;

        /** セッションタイムからボーナスタイムを抜いたベースタイム */
        private var _basetime:int;

        public function SessionTimer()
        {
            if (instance != null)
            {
                throw new IllegalOperationError("Only one TimerModel instance should be instantiated");
            }

            _utilTimer = new Timer(INTERVAL);
            _utilTimer.addEventListener(TimerEvent.TIMER, timerHandler);
        }

        public static function getInstance():SessionTimer
        {
            if (instance == null)
            {
                instance = new SessionTimer();
            }

            return instance;
        }

        /**
         * セッションタイム設定値取得
         *
         * @return セッションタイム
         */
        public function get period():int
        {
            return this._period;
        }

        /**
         * セッションタイムセット
         *
         * @param period セッションタイム
         */
        public function set period(period:int):void
        {
            if (period < this._bonus)
            {
                throw new ArgumentError("ボーナスタイム以下のセッションタイムは設定できません");
            }

            this._period = period;
            this._basetime = period - bonus;
        }

        /**
         * ボーナスタイム取得
         *
         * @return ボーナスタイム
         */
        public function get bonus():int
        {
            return this._bonus;
        }

        /**
         * ボーナスタイムセット
         *
         * @param period ボーナスタイム
         */
        public function set bonus(bonus:int):void
        {
            if (this._period < bonus)
            {
                throw new ArgumentError("セッションタイム以上のボーナスタイムは設定できません");
            }
            this._bonus = bonus;
            this._adjustedBonus = bonus;
            this._basetime = period - bonus;
        }

        public function get adjustedBonus():int
        {
            return this._adjustedBonus;
        }

        public function adjustBonus(value:int):void
        {
            if (this.remainingTime < this._basetime)
            {
                return;
            }

            var temp:int = this._adjustedBonus + value;
            if (temp > this._bonus)
            {
                temp = this._bonus;
            }
            else if (temp < 0)
            {
                temp = 0;
            }

            this._adjustedBonus = temp;
        }

        /**
         * ベースタイム取得
         *
         * @return ベースタイム
         */
        public function get basetime():int
        {
            var time:int = this._basetime - getTimer() + _startTime;

            return (time >= 0) ? time : 0;
        }

        /**
         * 残セッションタイム取得
         *
         * @return 残セッションタイム
         */
        public function get remainingTime():int
        {
            var time:int = this._basetime + this._adjustedBonus - getTimer() + _startTime;

            return (time >= 0) ? time : 0;
        }

        public function get running():Boolean
        {
            return this._utilTimer.running;
        }

        /**
         * セッションタイムを受けタイマー開始
         *
         * @param value セッションタイム設定値
         */
        public function start():void
        {
            if (!_utilTimer.running)
            {
                _startTime = getTimer();
                _utilTimer.start();
                dispatchEvent(new Event(Event.CHANGE));
            }
        }

        /**
         * タイマー停止
         */
        public function stop():void
        {
            if (_utilTimer.running)
            {
                _utilTimer.stop();
                dispatchEvent(new Event(Event.CHANGE));
            }
        }

        /**
         * タイマーリセット
         */
        public function reset():void
        {
            _utilTimer.reset();
            dispatchEvent(new Event(Event.CHANGE));
        }

        /**
         * 残タイム変更通知
         *
         * @param event タイマーイベント
         */
        private function timerHandler(event:TimerEvent):void
        {
            if (remainingTime <= 0)
            {
                stop();
                dispatchEvent(new SessionTimerEvent(SessionTimerEvent.TIME_UP));
            }

            dispatchEvent(new Event(Event.CHANGE));
        }
    }
}
